package com.yang.strategy.impl;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yang.config.RedisBloomFilter;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

import static com.yang.constants.RedisConstants.CACHE_NULL_TTL;
/**
 * <p>
 * 布隆过滤器解决缓存穿透
 * </p>
 * @author yang
 * @date 2023/8/13
 */
@Service("queryWithBloomFilterUtil")
public class QueryWithBloomFilterUtil extends AbstractCacheStrategyImpl{
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedisBloomFilter<Long> redisBloomFilter;

    @Override
    public <R, ID> R getCache(String keyPrefix, ID id, Class<R> type, Function<ID, R> dbFallback, Long time, TimeUnit unit) {
        // 判断数据是否存在
        boolean exist = redisBloomFilter.exist(Long.valueOf(id.toString()));

        //布隆过滤器判断不存在
        if (!exist){
            return null;
        }

        //拿到前缀和id，用来拼接key
        String key = keyPrefix + id;

        //通过key查询redis缓存
        String valueJson = stringRedisTemplate.opsForValue().get(key);

        //缓存命中，直接返回
        if (StrUtil.isNotBlank(valueJson)){
            return JSONUtil.toBean(valueJson,type);
        }

        //未命中，查询数据库
        R data = dbFallback.apply(id);

        //不存在，写入空值
        if (data == null){
            stringRedisTemplate.opsForValue().set(key,"",CACHE_NULL_TTL,TimeUnit.MINUTES);
            return null;
        }
        //存在写入redis
        super.setCache(key,data,time,unit,false);

        //写入布隆过滤器
        redisBloomFilter.put(Long.valueOf(id.toString()));

        //6.返回数据
        return data;
    }
}
